package utils

import (
	"context"
	"crypto/md5"
	"encoding/hex"
	"github.com/mholt/archives"
	"io"
	"log"
	"os"
	"path/filepath"
	"strings"
)

var TryDir = ""

func IsExist(path string) bool {
	_, err := os.Stat(path)
	if os.IsNotExist(err) {
		return false
	}
	return true
}

func TarXz(dst string, src string) error {
	ctx := context.TODO()

	src = filepath.Clean(src)
	dst = filepath.Clean(dst)
	if !strings.HasSuffix(src, string(os.PathSeparator)) {
		src += string(os.PathSeparator)
	}
	files, err := archives.FilesFromDisk(ctx, nil, map[string]string{
		src: "",
	})
	if err != nil {
		return err
	}

	out, err := os.Create(dst)
	if err != nil {
		return err
	}
	defer out.Close()
	var compression archives.Compression
	if strings.HasSuffix(dst, "gz") {
		compression = archives.Gz{}
	} else if strings.HasSuffix(dst, "xz") {
		compression = archives.Xz{}
	} else {
		compression = archives.Gz{}
	}
	format := archives.CompressedArchive{
		Compression: compression,
		Archival:    archives.Tar{},
	}
	err = format.Archive(context.Background(), out, files)
	if err != nil {
		return err
	}
	return nil
}

// UnTarXz 解压tar.gz文件
func UnTarXz(dst string, src string) error {

	src = filepath.Clean(src)

	srcFile, err := os.Open(src)
	if err != nil {
		return err
	}
	defer srcFile.Close()

	dst = filepath.Clean(dst)
	_, err = os.Stat(dst)
	if err != nil && !os.IsNotExist(err) {
		return err
	} else if err != nil {
		err = os.MkdirAll(dst, os.ModePerm)
	}
	if err != nil {
		return err
	}
	var compression archives.Compression
	if strings.HasSuffix(src, "gz") {
		compression = archives.Gz{}
	} else if strings.HasSuffix(src, "xz") {
		compression = archives.Xz{}
	} else {
		compression = archives.Gz{}
	}
	format := archives.CompressedArchive{
		Compression: compression,
		Archival:    archives.Tar{},
	}
	err = format.Extract(context.Background(), srcFile, func(ctx context.Context, info archives.FileInfo) error {
		path := filepath.Join(dst, info.Name())
		if info.IsDir() {
			err := os.MkdirAll(path, info.Mode())
			if err != nil {
				return err
			}
			return nil
		}
		file, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, info.Mode())
		if err != nil {
			return err
		}
		defer file.Close()
		temp, err := info.Open()
		if err != nil {
			return err
		}
		defer temp.Close()
		_, err = io.Copy(file, temp)
		return nil
	})

	return nil
}

func CalcMd5(content string) string {
	pass := md5.Sum([]byte(content))
	return hex.EncodeToString(pass[:])
}

func CalcFileMd5(filePath string) string {
	file, err := os.Open(filePath)
	if err != nil {
		log.Printf("open file fail: %v", err)
		return ""
	}
	defer file.Close()
	hash := md5.New()
	if _, err := io.Copy(hash, file); err != nil {
		log.Printf("read file fail: %v", err)
		return ""
	}
	return hex.EncodeToString(hash.Sum(nil))
}

func CopyFile(src, dst string) (err error) {
	in, err := os.Open(src)
	if err != nil {
		return
	}
	defer in.Close()

	out, err := os.Create(dst)
	if err != nil {
		return
	}
	defer out.Close()

	_, err = io.Copy(out, in)
	return
}

func GetAbsolutePath(path string) string {
	p, _ := filepath.Abs(path)
	if IsExist(p) {
		return p
	}
	if TryDir == "" {
		return path
	}
	p = filepath.Join(TryDir, path)
	if IsExist(p) {
		return p
	}
	return path
}
